using System.Collections;
using System.Collections.Generic;
using JufGame.ExMethod;
using UnityEngine;
using WeightAndBias = JufGame.WeightBiasMemory.LayerWeightAndBias;

namespace JufGame
{
	public class ANNCar : GAUnit
	{
		public Transform startPos;
		public Vector3[] direactions;
		public float[] rayLength;
		public LayerMask hitMask;
		public MLP myMLP;

		[Header("最后一个为转速，倒数第二个为移速")]
		[SerializeField] private float[] inputVal; 
		[SerializeField] private float distanceMultipler = 1.4f;
        [SerializeField] private float avgSpeedMultiplier = 0.2f;
        [SerializeField] private float sensorMultiplier = 0.1f;
		private Rigidbody rb;
		private Vector3 moveVel;
		private Vector3 lastPos;
		private float totalMoveDis, avgSpeed;
		private float runningTime, totalSensor;

        private void Start()
		{
			myMLP = new MLP(memory, 1);
			rb = GetComponent<Rigidbody>();
			ReStart();
		}

		private void FixedUpdate()
		{
			if(myMLP != null && !isOver)
			{
				CheckEnv();
				RunMLP();
				runningTime += Time.fixedDeltaTime;
				CalculateFitness();
				lastPos = transform.position;
			}
		}

		private void CheckEnv()
		{
			totalSensor = 0;
			for(int i = 0; i < direactions.Length; ++i)
			{
				var dir = transform.TransformDirection(direactions[i]);
				if(Physics.Raycast(transform.position, dir, out RaycastHit hit, 
					rayLength[i], hitMask, QueryTriggerInteraction.Ignore))
				{
					inputVal[i] = hit.distance / rayLength[i];
				}
				else
				{
					inputVal[i] = 1;
				}
				totalSensor += inputVal[i];
			}
		}

		private void RunMLP()
		{
			myMLP.Predict(inputVal);
			moveVel = transform.TransformDirection(new Vector3( 0, 0, myMLP.outputData[0] * 10));
			moveVel = Vector3.MoveTowards(rb.velocity, moveVel, 0.02f);
			rb.velocity = moveVel;
			transform.eulerAngles += new Vector3(0, myMLP.outputData[1] * 90 * Time.fixedDeltaTime, 0);
		}
		
		private void CalculateFitness()
		{
			totalMoveDis += Vector3.Distance(transform.position, lastPos);
			avgSpeed = totalMoveDis / runningTime;
			//适应度 与 位移距离、 速度、 检测距离 有关
			FitNess = (totalMoveDis*distanceMultipler) + (avgSpeed*avgSpeedMultiplier) + ( totalSensor / inputVal.Length *sensorMultiplier);
			if (runningTime > 20 && FitNess < 40) //存活足够时间且适应度不低时，结束本轮
			{
				isOver = true;
			}
			if(FitNess >= 1000) //适应度很高时，直接算成功，结束
			{
				isOver = true;
			}
		}

		public override void ReStart()
		{
			base.ReStart();
			transform.SetPositionAndRotation(startPos.position, startPos.rotation);
            runningTime = 0;
			totalMoveDis = 0;
			lastPos = startPos.position;
		}

		private void OnCollisionEnter(Collision other)
		{
			if(!isOver && hitMask.ContainLayer(other.gameObject.layer))
			{
				isOver = true;
				rb.velocity = Vector3.zero;
			}
		}

		private void OnDrawGizmos()
		{
			for(int i = 0; i < direactions.Length; ++i)
			{
				var dir = transform.TransformDirection(direactions[i]);
				Gizmos.color = new Color(1 * (i + 1.0f) / direactions.Length, 0, 0, 1);
				var origin = transform.position;
				Gizmos.DrawRay(origin, dir.normalized * rayLength[i]);
			}
		}
	}
}
